#include "thread_pool.h"
#include <dirent.h>
#include "user_check.h"
#include "link_list.h"
#include "user_register.h"
#include "datebase.h"
#include "str_util.h"

extern ListNode *userList;

//主线程调用:处理客户端发过来的消息
void handleMessage(int sockfd, int epfd, task_queue_t * que,
                   MYSQL_STMT * stmt, MYSQL pconn)
{
    //消息格式：cmd content
    //1.1 获取消息长度
    int length = -1;
    int ret = recvn(sockfd, &length, sizeof(length));
    printf("recv length: %d\n", length);

    //1.2 获取消息类型
    int cmdType = -1;
    ret = recvn(sockfd, &cmdType, sizeof(cmdType));
    printf("recv cmd type: %d\n", cmdType);
    task_t *ptask = (task_t *) calloc(1, sizeof(task_t));
    ptask->peerfd = sockfd;
    ptask->type = (CmdType) cmdType;
    ptask->epfd = epfd;
    ptask->stmt = stmt;
    ptask->pconn = pconn;

    if (length > 0) {
        //1.3 获取消息内容
        ret = recvn(sockfd, ptask->data, length);
        if (ret > 0) {
            //if (ptask->type == CMD_TYPE_PUTS) {
            //delEpollReadfd(epfd, sockfd);
            //}
            //往线程池中添加任务
            taskEnque(que, ptask);
        }
    } else if (length == 0) {
        taskEnque(que, ptask);
    }

    if (ret == 0) {		//连接断开的情况
        printf("\nconn %d is closed.\n", sockfd);
        delEpollReadfd(epfd, sockfd);
        close(sockfd);
        //deleteNode2(&userList,sockfd);//mcxadd
    }
}

//注意：此函数可以根据实际的业务逻辑，进行相应的扩展
void doTask(task_t * task)
{
    
    //添加用户操作日志
    addUseLog(task);
    assert(task);
    switch (task->type) {
    case CMD_TYPE_PWD:
        pwdCommand(task);
        break;
    case CMD_TYPE_CD:
        cdCommand(task);
        break;
    case CMD_TYPE_LS:
        lsCommand(task);
        break;
    case CMD_TYPE_MKDIR:
        mkdirCommand(task);
        break;
    case CMD_TYPE_RMDIR:
        rmdirCommand(task);
        break;
    case CMD_TYPE_NOTCMD:
        notCommand(task);
        break;
    case CMD_TYPE_PUTS:
        delEpollReadfd(task->epfd,task->peerfd);
        putsCommand(task);
        addEpollReadfd(task->epfd, task->peerfd);
        break;
    case CMD_TYPE_GETS:
        delEpollReadfd(task->epfd,task->peerfd);
        getsCommand(task);
        addEpollReadfd(task->epfd, task->peerfd);
        break;
    case TASK_LOGIN_SECTION1:
        userLoginCheck1(task);
        break;
    case TASK_LOGIN_SECTION2:
        userLoginCheck2(task);
        break;
    case TASK_REGISTER_SECTION1:
        userRegister1(task);
        break;
    case TASK_REGISTER_SECTION2:
        userRegister2(task);
        break;
    }
}

//每一个具体任务的执行，交给一个成员来实现
MYSQL_RES* execute_query(MYSQL *conn, const char *query)
{
    if (mysql_query(conn, query))
    {
        fprintf(stderr, "%s\n", mysql_error(conn));
        return NULL;
    }
    return mysql_store_result(conn);
}

char *pwdCommand(task_t * task)
{
#if 1
    ListNode *curr_node = userList;
    user_info_t *curr_user = (user_info_t *)curr_node->val;

    // 获取当前用户信息
    while(curr_node != NULL)
    {
        if(curr_user->sockfd == task->peerfd)
        {
            break;
        }
        curr_node = curr_node->next;
        curr_user = curr_node->val;
    } // curr_node = NULL || curr_user->sockfd = task->peerfd

    // curr_node = NULL;
    if(curr_node == NULL)
    {
        char *error_msg = "User not exist!";
        sendn(task->peerfd, error_msg, strlen(error_msg));

        return NULL;
    }
    // curr_user->sockfd = task->peerfd
#endif
    char query[1024];
#if 1
    snprintf(query, sizeof(query),
             "WITH RECURSIVE directory_path AS ("
             " SELECT id, filename, parent_id, filename AS path"
             " FROM file_table"
             " WHERE id = %d and owner_id = %d"
             " UNION ALL"
             " SELECT d.id, d.filename, d.parent_id, CONCAT(d.filename, '/', dp.path)"
             " FROM file_table AS d"
             " JOIN directory_path AS dp ON dp.parent_id = d.id"
             ")"
             " SELECT path FROM directory_path where parent_id = 0;", curr_user->pwd, curr_user->user_id);
#endif

    MYSQL_RES *result = execute_query(&(task->pconn), query);
    if (!result)
    {
        perror("mysql_query error");
        const char *error_msg = "Failed to query current directory.";
        int ret = sendn(task->peerfd, error_msg, strlen(error_msg));
        if (ret == -1)
        {
            perror("sendn error");
        }
        else
        {
            printf("Sent %d bytes to client.\n", ret);
        }
        return NULL;
    }

    MYSQL_ROW row;
    if ((row = mysql_fetch_row(result)))
    {
        printf("execute pwd command.\n");

        // 将目录路径存储到 task->data 中
        strncpy(task->data, row[0], sizeof(task->data));
        task->data[sizeof(task->data) - 1] = '\0'; // 确保字符串以 NULL 结尾
                                                   // 清理多余的斜杠
        for (size_t i = 1; i < strlen(task->data); ++i)
        {
            if (task->data[i] == '/' && task->data[i - 1] == '/')
            {
                memmove(&task->data[i], &task->data[i + 1], strlen(&task->data[i + 1]) + 1);
                --i;
            }
        }
        // 将路径通过 peerfd 发送回客户端
        int ret = sendn(task->peerfd, task->data, strlen(task->data));
        if (ret == -1)
        {
            perror("sendn error");
        }
        else
        {
            printf("Sent %d bytes to client.\n", ret);
        }
    }
    else
    {
        perror("mysql_fetch_row() error");
    }

    mysql_free_result(result);

    return task->data;
}

void lsCommand(task_t *task)
{
    // 打印调试信息，表示进入了 lsCommand 函数。
    printf("Entering lsCommand\n");

    int user_id = 0;
    ListNode *pNode = userList;
    user_info_t *user = NULL;

    // 遍历 userList 链表以找到与当前任务关联的用户。
    while (pNode != NULL)
    {
        // 获取当前节点中的用户信息。
        user = (user_info_t *)pNode->val;
        // 如果用户的 sockfd 与任务的 peerfd 匹配，则找到了当前用户。
        if (user->sockfd == task->peerfd)
        {
            // 获取用户 ID。
            user_id = user->user_id;
            break;
        }
        // 继续遍历下一个节点。
        pNode = pNode->next;
    }

    // 如果用户为空，表示没有找到用户，输出错误并返回。
    if (user == NULL)
     {
         fprintf(stderr, "User not found.\n");
         printf("Exiting lsCommand\n");
         return;
     }
 
     // 获取用户的当前工作目录 ID。
     int parent_id = user->pwd;
 
     // 初始化 MySQL 语句句柄。
     MYSQL_STMT *stmt = mysql_stmt_init(&(task->pconn));
     if (!stmt)
     {
         // 如果初始化失败，输出错误并返回。
         fprintf(stderr, "mysql_stmt_init() failed\n");
         printf("Exiting lsCommand\n");
         return;
     }
 
     // 准备 SQL 查询语句。
     const char *sql = "SELECT filename, type FROM file_table WHERE owner_id = ? AND parent_id = ? AND exist = 1";
     if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
     {
         // 如果准备语句失败，输出错误并关闭句柄，返回。
         fprintf(stderr, "mysql_stmt_prepare() failed\n");
         fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
         mysql_stmt_close(stmt);
         printf("Exiting lsCommand\n");
         return;
     }
    // 准备绑定参数。
    MYSQL_BIND bind[2];
    memset(bind, 0, sizeof(bind));

    // 绑定第一个参数：用户 ID。
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char *)&user_id;
    bind[0].is_null = 0;
    bind[0].length = 0;

    // 绑定第二个参数：当前工作目录 ID。
    bind[1].buffer_type = MYSQL_TYPE_LONG;
    bind[1].buffer = (char *)&parent_id;
    bind[1].is_null = 0;
    bind[1].length = 0;

    // 将参数绑定到 SQL 语句。
    if (mysql_stmt_bind_param(stmt, bind))
    {
        // 如果绑定参数失败，输出错误并关闭句柄，返回。
        fprintf(stderr, "mysql_stmt_bind_param() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        printf("Exiting lsCommand\n");
        return;
    }

    // 执行 SQL 查询。
    if (mysql_stmt_execute(stmt))
    {
        // 如果执行查询失败，输出错误并关闭句柄，返回。
        fprintf(stderr, "mysql_stmt_execute() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        printf("Exiting lsCommand\n");
        return;
    }

    // 准备绑定结果。
    MYSQL_BIND result_bind[2];
    memset(result_bind, 0, sizeof(result_bind));

    char filename[256]; // 存储文件名的缓冲区。
    char type[2]; // 存储文件类型的缓冲区，假设类型值为 'd' 或 'f'。

    // 绑定第一个结果列：文件名。
    result_bind[0].buffer_type = MYSQL_TYPE_STRING;
    result_bind[0].buffer = filename;
    result_bind[0].buffer_length = sizeof(filename);
    result_bind[0].is_null = 0;
    result_bind[0].length = 0;

    // 绑定第二个结果列：文件类型。
    result_bind[1].buffer_type = MYSQL_TYPE_STRING;
    result_bind[1].buffer = type;
    result_bind[1].buffer_length = sizeof(type);
    result_bind[1].is_null = 0;
    result_bind[1].length = 0;

    // 将结果绑定到 SQL 语句。
    if (mysql_stmt_bind_result(stmt, result_bind))
    {
        // 如果绑定结果失败，输出错误并关闭句柄，返回。
        fprintf(stderr, "mysql_stmt_bind_result() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        printf("Exiting lsCommand\n");
        return;
    }

    // 准备响应头部消息。
    char response[512];
    snprintf(response, sizeof(response), "Listing files and directories:\n");
    // 发送响应头给客户端。
    send(task->peerfd, response, strlen(response), 0);

    // 逐行获取查询结果并发送给客户端。
    while (mysql_stmt_fetch(stmt) == 0)
    {
        // 格式化每一行结果，文件类型为目录时在文件名后添加 '/'，用多个空格作为分隔符。
        snprintf(response, sizeof(response), "%s%s    ", filename, (strcmp(type, "d") == 0) ? "/" : "");
        // 发送结果给客户端。
        send(task->peerfd, response, strlen(response), 0);
    }

    // 发送换行符来结束输出。
    send(task->peerfd, "\n", 1, 0);
 
     // 关闭 SQL 语句句柄以释放资源。
     mysql_stmt_close(stmt);
     // 打印调试信息，表示退出了 lsCommand 函数。
     printf("Exiting lsCommand\n");
 }
 



int getParentDirId(task_t task, int user_id, int dir_id)
{
    // 实现获取父目录ID的逻辑
    const char *sql = "SELECT parent_id FROM file_table WHERE id = ? AND owner_id = ? AND exist = 1";
    MYSQL_STMT *stmt = task.stmt;
    if (!stmt)
    {
        fprintf(stderr, "mysql_stmt_init() failed\n");
        return -1;
    }

    if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
    {
        fprintf(stderr, "mysql_stmt_prepare() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    MYSQL_BIND bind[2];
    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char *)&dir_id;
    bind[0].is_null = 0;
    bind[0].length = 0;

    bind[1].buffer_type = MYSQL_TYPE_LONG;
    bind[1].buffer = (char *)&user_id;
    bind[1].is_null = 0;
    bind[1].length = 0;

    if (mysql_stmt_bind_param(stmt, bind))
    {
        fprintf(stderr, "mysql_stmt_bind_param() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    if (mysql_stmt_execute(stmt))
    {
        fprintf(stderr, "mysql_stmt_execute() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    int parent_id;
    MYSQL_BIND result_bind[1];
    memset(result_bind, 0, sizeof(result_bind));

    result_bind[0].buffer_type = MYSQL_TYPE_LONG;
    result_bind[0].buffer = (char *)&parent_id;
    result_bind[0].is_null = 0;
    result_bind[0].length = 0;

    if (mysql_stmt_bind_result(stmt, result_bind))
    {
        fprintf(stderr, "mysql_stmt_bind_result() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    if (mysql_stmt_fetch(stmt) != 0)
    {
        parent_id = -1;
    }

    /* mysql_stmt_close(stmt); */
    return parent_id;
}

int updateUserPwd(task_t task, int user_id, int pwd)
{
    MYSQL_STMT *stmt = task.stmt;
    if (!stmt)
    {
        fprintf(stderr, "mysql_stmt_init() failed\n");
        return -1;
    }

    const char *sql = "UPDATE user_table SET pwd = ? WHERE id = ?";

    if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
    {
        fprintf(stderr, "mysql_stmt_prepare() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    MYSQL_BIND bind[2];
    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char *)&pwd;
    bind[0].is_null = 0;
    bind[0].length = 0;

    bind[1].buffer_type = MYSQL_TYPE_LONG;
    bind[1].buffer = (char *)&user_id;
    bind[1].is_null = 0;
    bind[1].length = 0;

    if (mysql_stmt_bind_param(stmt, bind))
    {
        fprintf(stderr, "mysql_stmt_bind_param() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    if (mysql_stmt_execute(stmt))
    {
        fprintf(stderr, "mysql_stmt_execute() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    /* mysql_stmt_close(stmt); */
    return 0;
}
int getDirId(task_t task, int user_id, int parent_id, const char *dir_name)
{
    MYSQL_STMT *stmt = task.stmt;
    if (!stmt)
    {
        fprintf(stderr, "mysql_stmt_init() failed\n");
        return -1;
    }

    const char *sql = "SELECT id FROM file_table WHERE owner_id = ? AND parent_id = ? AND filename = ? AND exist = 1 AND type = 'd'";

    if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
    {
        fprintf(stderr, "mysql_stmt_prepare() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    MYSQL_BIND bind[3];
    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char *)&user_id;
    bind[0].is_null = 0;
    bind[0].length = 0;

    bind[1].buffer_type = MYSQL_TYPE_LONG;
    bind[1].buffer = (char *)&parent_id;
    bind[1].is_null = 0;
    bind[1].length = 0;

    bind[2].buffer_type = MYSQL_TYPE_STRING;
    bind[2].buffer = (char *)dir_name;
    bind[2].buffer_length = strlen(dir_name);
    bind[2].is_null = 0;
    bind[2].length = 0;

    if (mysql_stmt_bind_param(stmt, bind))
    {
        fprintf(stderr, "mysql_stmt_bind_param() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    if (mysql_stmt_execute(stmt))
    {
        fprintf(stderr, "mysql_stmt_execute() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    MYSQL_BIND result_bind[1];
    memset(result_bind, 0, sizeof(result_bind));

    int dir_id;
    result_bind[0].buffer_type = MYSQL_TYPE_LONG;
    result_bind[0].buffer = (char *)&dir_id;
    result_bind[0].is_null = 0;
    result_bind[0].length = 0;

    if (mysql_stmt_bind_result(stmt, result_bind))
    {
        fprintf(stderr, "mysql_stmt_bind_result() failed\n");
        fprintf(stderr, "%s\n", mysql_stmt_error(stmt));
        /* mysql_stmt_close(stmt); */
        return -1;
    }

    if (mysql_stmt_fetch(stmt) == 0)
    {
        /* mysql_stmt_close(stmt); */
        return dir_id;
    }
    else
    {
        /* mysql_stmt_close(stmt); */
        return -1;
    }
}
void cdCommand(task_t *task)
{
    task_t t = *task;
    char *path = strtok(task->data, " "); // 处理task->data后面的空格
    printf("%s\n", path);
    char *tokens[10] = {0};
    int count = 0;
    new_splitString(path, "/", tokens, 10, &count); // 将路径分割为目录数组

    int user_id = 0;
    char *username = NULL;
    ListNode *pNode = userList;
    user_info_t *user = (user_info_t *)pNode->val;
    while (pNode != NULL)
    {
        if (user->sockfd == task->peerfd)
        {
            user_id = user->user_id; // 获取用户id
            username = user->name;
            break;
        }
        else
        {
            pNode = pNode->next;
        }
    }

    int parent_id = user->pwd; // 从当前目录开始

    for (int i = 0; i < count; i++)
    {
        if (strcmp(tokens[i], ".") == 0)
        {
            continue; // 当前目录，什么都不做
        }
        else if (strcmp(tokens[i], "..") == 0)
        {
            printf("user_id: %d, parent_id: %d\n", user_id, parent_id);
            // 获取父目录的ID
            int tmp = getParentDirId(*task, user_id, parent_id);
            if(!tmp){
                continue;
            }
            else {
                parent_id = tmp;
            }
            if (parent_id == -1)
            {
                fprintf(stderr, "Failed to access parent directory.\n");
                return;
            }
        }
        else
        {
            printf("user_id: %d, parent_id: %d, tokens[i]: %s",  user_id, parent_id, tokens[i]);
            int dir_id = getDirId(*task, user_id, parent_id, tokens[i]);
            if (dir_id == -1)
            {
                fprintf(stderr, "Directory '%s' not found or access denied.\n", tokens[i]);
                return;
            }
            parent_id = dir_id; // 更新parent_id为当前目录的id
        }
    }

    user->pwd = parent_id;
    // 更新用户的虚拟路径
    if (updateUserPwd(*task, user_id, parent_id) != 0)
    {
        fprintf(stderr, "Failed to update user pwd.\n");
        return;
    }

    printf("Directory changed successfully\n");
}

void mkdirCommand(task_t * task)
{
    printf("mkdirCommand \n");
    ListNode *pNode = userList;
    while (pNode != NULL) {
        user_info_t *user = (user_info_t *) pNode->val;
        if (user->sockfd == task->peerfd) {
            MYSQL_STMT* stmt=task->stmt;
            MYSQL pconn=task->pconn;
            printf("user_name=%s\n",user->name);
            user->user_id=select_userid(user->name,stmt,pconn);
            printf("user_id=%d\n",user->user_id);
            insert_filetable(user->pwd,task->data,user->user_id,stmt,pconn);
            return;
        } else {
            pNode = pNode->next;
        }
    }

}

void rmdirCommand(task_t * task)
{
printf("rmdirCommand \n");
        ListNode *pNode = userList;
        while (pNode != NULL) {
            user_info_t *user = (user_info_t *) pNode->val;
            if (user->sockfd == task->peerfd) {
                MYSQL_STMT *stmt =task->stmt;
                MYSQL pconn=task->pconn;
                int id=getDirid(&pconn,user->user_id,user->pwd,task->data);
                printf("id=%d\n",id);
                printf("pwd=%d\n",user->pwd);
                printf("name=%s\n",task->data);
                updateExit(pconn, stmt, id);
                return;
            } else {
                pNode = pNode->next;
            }
        }
   }

void notCommand(task_t * task)
{
    printf("Not a command.\n");
    char err_msg[] = "This is not a command!!";
    send(task->peerfd, err_msg, sizeof(err_msg), 0);

}

//--------------------------------------------------------------
//第一期puts和gets
/*
   void putsCommand(task_t * task)
   {
   printf("execute puts command.\n");

// 打印接收到的数据（文件名）
if (task->data[0] == '\0') {
printf("Invalid filename.\n");
return;
}
printf("Received filename: %s\n", task->data);

// 复制文件名
char filename[256] = { 0 };
strncpy(filename, task->data, sizeof(filename) - 1);

// 打开文件以写入
FILE *fp = fopen(filename, "wb");
if (!fp) {
perror("fopen");
return;
}
// 接收文件大小
int file_size;
int ret = recvn(task->peerfd, &file_size, sizeof(file_size));
if (ret <= 0) {
if (ret == 0) {
printf("Connection closed while receiving file size.\n");
} else {
perror("recvn error");
}
fclose(fp);
return;
}
printf("File size: %d\n", file_size);

// 接收文件数据
int received_size = 0;
while (received_size < file_size) {
int chunk_size =
(file_size - received_size >
sizeof(task->data)) ? sizeof(task->data) : (file_size -
received_size);
ret = recvn(task->peerfd, task->data, chunk_size);
if (ret <= 0) {
if (ret == 0) {
printf("Connection closed while receiving file data.\n");
} else {
perror("recvn error");
}
break;
}
fwrite(task->data, 1, ret, fp);
received_size += ret;
}

// 关闭文件
fclose(fp);

// 检查文件是否接收完整
if (received_size == file_size) {
printf("File received successfully.\n");
} else {
printf("File received incomplete. Received size: %d\n",
received_size);
}

// 任务完成后重新添加 fd 到 epoll
addEpollReadfd(task->epfd, task->peerfd);
}


void getsCommand(task_t * task)
{
    printf("execute gets command.\n");
    char *path = strtok(task->data, " ");	//task->data后面多了一个空格，进行处理
    simpleTransferFile(task->peerfd, path);
    printf("finish gets.\n");
}
*/
//第一期puts和gets
//--------------------------------------------------------------------------------

/*
//MCX:BEGIN:2ND GETS&PUTS------------------------------------------------------------------------
void putsCommand(task_t * task) {
printf("execute puts command.\n");
printf("fileName:%s<\n",task->data);
char pathname[1024] = {0};
sprintf(pathname,"./%s",task->data);
int filefd = open(pathname,O_RDWR|O_CREAT,0666);
if(filefd == -1)
{
perror("open file");
}

struct stat filestat;
int ret = fstat(filefd,&filestat);
if(ret == -1)
{
perror("fstat");
}

int filesize;
recv(task->peerfd,&filesize,sizeof(int),0);
printf("recv filesize:%d\n",filesize);


int currsize = filestat.st_size;
printf("file currsize:%d\n",currsize);
off_t offset = lseek(filefd,currsize,SEEK_SET);
printf("offset:%ld\n",offset);
sendn(task->peerfd,&offset,sizeof(off_t));//传已有文件偏移量

char buffer[1024];
memset(buffer,0,sizeof(buffer));

int after_size =filesize-offset;
printf("To be recv size:%d\n",after_size);

ftruncate(filefd,filesize);

char *pMap = (char *)mmap(NULL,after_size,PROT_READ|PROT_WRITE,MAP_SHARED,filefd,0);
if(pMap)
{
printf("after mmap\n");
recv(task->peerfd,pMap=pMap+offset,after_size,MSG_WAITALL);
}
printf("recv file successfully\n");
munmap(pMap,after_size);

close(filefd);
}

void getsCommand(task_t * task) {
printf("execute gets command.\n");
char pathname[1024] = {0};
sprintf(pathname,"%s",task->data);
printf("filename>%s<\n",pathname);
int filefd = open(pathname,O_RDONLY);
if(filefd == -1)
{
perror("open file");
}

struct stat filestat;
int ret = fstat(filefd,&filestat);
if(ret == -1)
{
perror("fstat");
}
int filesize = filestat.st_size;
printf("fliesize:%d\n",filesize);
sendn(task->peerfd,&filesize,sizeof(int));
printf("sendn over\n");

off_t offset;
recvn(task->peerfd,&offset,sizeof(off_t));
printf("recv offset:%ld\n",offset);
int size_after = filesize - offset;


char *pMap = (char *)mmap(NULL,size_after,PROT_READ,MAP_SHARED,filefd,0);
if(pMap)
{
    printf("after mmap\n");
    send(task->peerfd,pMap=pMap+offset,size_after,0);
}

printf("send file successfully\n");
munmap(pMap,size_after);

close(filefd);

}
//mcx:END:2nd puts&gets-------------------------------------------------------------------
*/


void putsCommand(task_t * task) {//只有表里没有md5的残余文件才能断点续传
    printf("execute puts command.\n");

    int filesize;
    int user_id = 0;
    int pwd = 0;
    ListNode *pNode = userList;
    user_info_t *user = (user_info_t *)pNode->val;
    while (pNode != NULL)
    {
        if (user->sockfd == task->peerfd)
        {
            user_id = user->user_id; // 获取用户id
            pwd = user->pwd;                         
            break;
        }
        else
        {
            pNode = pNode->next;
        }
    }
    char md5_result[33] ;
    md5_result[32] = '\0';
    int md5check;
    recv(task->peerfd,md5_result,33,0);
    printf("pwd:%d\n",pwd);
    if(check_filename_exists_with_pwd(task->data,pwd,&task->pconn))
    {
        md5check = -1;
        send(task->peerfd,&md5check,sizeof(int),0);
        printf("filename exists in pwd!\n");
        return;
    }
    if((md5check=if_md5_exist(md5_result,33,&filesize,task->stmt,&task->pconn)) == true)
    {
        send(task->peerfd,&md5check,sizeof(int),0);
        printf("md5 exist!\n");
        goto successful;
    }
    send(task->peerfd,&md5check,sizeof(int),0);
    printf("md5 does not exit!\n");

    printf("fileName:%s<\n",task->data);
    char pathname[1024] = {0};
    sprintf(pathname,"./%s/%s","file_pool",md5_result);
    int filefd = open(pathname,O_RDWR|O_CREAT,0666);
    if(filefd == -1)
    {
        perror("open file");
    }

    struct stat filestat;
    int ret = fstat(filefd,&filestat);
    if(ret == -1)
    {
        perror("fstat");
    }

    recv(task->peerfd,&filesize,sizeof(int),0);
    printf("recv filesize:%d\n",filesize);


    int currsize = filestat.st_size;
    printf("file currsize:%d\n",currsize);
    off_t offset = lseek(filefd,currsize,SEEK_SET);
    printf("offset:%ld\n",offset);
    sendn(task->peerfd,&offset,sizeof(off_t));//传已有文件偏移量

    char buffer[1024];
    memset(buffer,0,sizeof(buffer));

    int after_size =filesize-offset;
    printf("To be recv size:%d\n",after_size);

    ftruncate(filefd,filesize);

    char *pMap = (char *)mmap(NULL,after_size,PROT_READ|PROT_WRITE,MAP_SHARED,filefd,0);
    if(pMap)
    {
        printf("after mmap\n");
        recv(task->peerfd,pMap=pMap+offset,after_size,MSG_WAITALL);
    }
    munmap(pMap,after_size);

    printf("recv file successful!\n");
    close(filefd);

successful:
    printf("rapid transfer!\n");
    printf("md5:%s<\n",md5_result);
    insert_puts_file(&task->pconn,task->stmt,pwd,task->data,user_id,md5_result,33,filesize);
}





void getsCommand(task_t * task) {
    printf("execute gets command.\n");
    int pwd = 0;
    ListNode *pNode = userList;
    user_info_t *user = (user_info_t *)pNode->val;
    while (pNode != NULL)
    {
        if (user->sockfd == task->peerfd)
        {
            pwd = user->pwd;
            break;
        }
        else
        {
            pNode = pNode->next;
        }
    }

    char pathname[1024] = {0};
    char md5_result[33] = {0};
    md5_result[32] = '\0';
    int file_check;
    if((file_check = get_md5_by_filename(pwd,task->data,md5_result,task->stmt,&task->pconn))==0)
    {
        send(task->peerfd,&file_check,sizeof(int),0);
        printf("FAIL IN GETS FILE CHECK\n");
        return; 
    }
    send(task->peerfd,&file_check,sizeof(int),0);
    printf("filecheck:%d\n",file_check);

    sprintf(pathname,"./%s/%s","file_pool",md5_result);
    printf("pathname>%s<\n",pathname);
    int filefd = open(pathname,O_RDONLY);
    if(filefd == -1)
    {
        perror("open file");
    }

    struct stat filestat;
    int ret = fstat(filefd,&filestat);
    if(ret == -1)
    {
        perror("fstat");
    }
    int filesize = filestat.st_size;
    printf("fliesize:%d\n",filesize);
    sendn(task->peerfd,&filesize,sizeof(int));
    printf("sendn over\n");

    off_t offset;
    recvn(task->peerfd,&offset,sizeof(off_t));
    printf("recv offset:%ld\n",offset);
    int size_after = filesize - offset;
    printf("to be send size:%d\n",size_after);

    char *pMap = (char *)mmap(NULL,size_after,PROT_READ,MAP_SHARED,filefd,0);
    if(pMap)
    {
        printf("after mmap\n");
        if(size_after != 0)
        {
        send(task->peerfd,pMap=pMap+offset,size_after,0);
        }
    }

    printf("send file successfully\n");
    munmap(pMap,size_after);

    
    close(filefd);

}





void deleteDir(const char *path)
{
    printf("%s\n", path);
    DIR *stream = opendir(path);
    struct dirent *pdirent;
    while ((pdirent = readdir(stream)) != NULL) {
        char *name = pdirent->d_name;
        // printf("%s\n",name);
        if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
            continue;
        }
        char a[1024];
        sprintf(a, "%s/%s", path, name);
        if (pdirent->d_type == DT_DIR) {
            deleteDir(a);
        } else if (pdirent->d_type == DT_REG) {
            unlink(a);
        }
    }
    closedir(stream);
    rmdir(path);
}

void userLoginCheck1(task_t * task)
{
    printf("userLoginCheck1 \n");
    ListNode *pNode = userList;
    while (pNode != NULL) {
        user_info_t *user = (user_info_t *) pNode->val;
        if (user->sockfd == task->peerfd) {
            strcpy(user->name, task->data);
            MYSQL_STMT* stmt=task->stmt;
            MYSQL pconn=task->pconn;

            loginCheck1(user,stmt,pconn);
            return;
        } else {
            pNode = pNode->next;
        }
    }
}

void userLoginCheck2(task_t * task)
{
    printf("userLoginCheck2.\n");
    ListNode *pNode = userList;
    while (pNode != NULL) {
        user_info_t *user = (user_info_t *) pNode->val;
        if (user->sockfd == task->peerfd) {
            loginCheck2(user, task->data,task->stmt,task->pconn);
            return;
        } else {
            pNode = pNode->next;
        }
    }

}

void userRegister1(task_t * task)
{
    printf("userRegister1\n");
    ListNode *pNode = userList;
    while (pNode != NULL) {
        user_info_t *user = (user_info_t *) pNode->val;
        if (user->sockfd == task->peerfd) {
            strcpy(user->name, task->data);
            MYSQL_STMT *stmt = task->stmt;
            MYSQL pconn = task->pconn;

            Register1(user, stmt, pconn);
            return;
        } else {
            pNode = pNode->next;
        }
    }
}

void userRegister2(task_t * task)
{
    printf("userRegister2\n");
    ListNode* pNode=userList;
    while(pNode!=NULL){
        user_info_t* user=(user_info_t*)pNode->val;
        if(user->sockfd==task->peerfd){
            strcpy(user->encrypted,task->data);
            MYSQL_STMT *stmt=task->stmt;
            MYSQL pconn=task->pconn;
            Register2(user,stmt,pconn);

            return;
        }else{
            pNode=pNode->next;
        }
    }

}
